/*
 * Copyright (C) 2004 NNL Technology AB
 * Visit www.infonode.net for information about InfoNode(R) 
 * products and how to contact NNL Technology AB.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, 
 * MA 02111-1307, USA.
 */

// $Id: SlopedTabLineBorder.java,v 1.3 2005/02/16 11:28:14 jesper Exp $

package net.infonode.tabbedpanel.internal;

import net.infonode.gui.colorprovider.ColorProvider;
import net.infonode.gui.colorprovider.UIManagerColorProvider;
import net.infonode.gui.shaped.border.AbstractPolygonBorder;

import java.awt.*;

/**
 * @author johan
 * @since 1.2.0
 */
public class SlopedTabLineBorder extends AbstractPolygonBorder {
	private static final long serialVersionUID = 1;

	private static final int[][][] corners = { { { 0, 0 }, { -1, 0, 0, -1 }, { -2, 0, -1, -1, 0, -1 }, { -4, 0, -3, -1, -2, -1, -1, -2, -1, -3, 0, -4 }, },
			{ { 0, 0 }, { 0, 0 }, { 0, 1, 1, 1, 2, 0 }, { 0, 4, 1, 3, 1, 2, 2, 1, 3, 1, 4, 0 }, },
			{ { 0, 0 }, { 0, 0 }, { -2, 0, -1, 1, 0, 1 }, { -4, 0, -3, 1, -2, 1, -1, 2, -1, 3, 0, 4 } },
			{ { 0, 0 }, { 0, -1, 1, 0 }, { 0, -1, 1, -1, 2, 0 }, { 0, -4, 1, -3, 1, -2, 2, -1, 3, -1, 4, 0 }, },
			{ { 0, 0 }, { 0, 0 }, { 0, 2, 1, 1, 1, 0 }, { 0, 4, 1, 3, 1, 2, 2, 1, 3, 1, 4, 0 }, },
			{ { 0, 0 }, { 0, 0 }, { -1, 0, -1, 1, 0, 2 }, { -4, 0, -3, 1, -2, 1, -1, 2, -1, 3, 0, 4 }, }, };

	private boolean drawBottomLine;
	private float leftSlope;
	private float rightSlope;
	private boolean bottomLeftRounded;
	private boolean topLeftRounded;
	private boolean topRightRounded;
	private boolean bottomRightRounded;
	private int leftHeight;
	private int rightHeight;

	private static int[] xCoords = new int[100];
	private static int[] yCoords = new int[100];
	private static int x;

	public static int getX() {
		return x;
	}

	public static void setX(int x) {
		SlopedTabLineBorder.x = x;
	}

	private static int y;

	public static int getY() {
		return y;
	}

	public static void setY(int y) {
		SlopedTabLineBorder.y = y;
	}

	private static int index;

	public static int getIndex() {
		return index;
	}

	public static void setIndex(int index) {
		SlopedTabLineBorder.index = index;
	}

	public SlopedTabLineBorder() {
		this(0, 1);
	}

	public SlopedTabLineBorder(float leftSlope, float rightSlope) {
		this(leftSlope, rightSlope, 22, 22);
	}

	public SlopedTabLineBorder(float leftSlope, float rightSlope, int leftHeight, int rightHeight) {
		this(leftSlope, rightSlope, leftHeight, rightHeight, false, false, false, false);
	}

	public SlopedTabLineBorder(float leftSlope, float rightSlope, boolean bottomLeftRounded, boolean topLeftRounded, boolean topRightRounded,
			boolean bottomRightRounded) {
		this(leftSlope, rightSlope, 22, 22, bottomLeftRounded, topLeftRounded, topRightRounded, bottomRightRounded);
	}

	public SlopedTabLineBorder(float leftSlope, float rightSlope, int leftHeight, int rightHeight, boolean bottomLeftRounded, boolean topLeftRounded,
			boolean topRightRounded, boolean bottomRightRounded) {
		this(UIManagerColorProvider.TABBED_PANE_DARK_SHADOW, UIManagerColorProvider.TABBED_PANE_HIGHLIGHT, false, leftSlope, rightSlope, leftHeight,
				rightHeight, bottomLeftRounded, topLeftRounded, topRightRounded, bottomRightRounded);
	}

	public SlopedTabLineBorder(ColorProvider lineColor, ColorProvider highlightColor, boolean drawBottomLine, float leftSlope, float rightSlope,
			int leftHeight, int rightHeight, boolean bottomLeftRounded, boolean topLeftRounded, boolean topRightRounded, boolean bottomRightRounded) {
		super(lineColor, highlightColor);
		this.drawBottomLine = drawBottomLine;
		this.leftHeight = leftHeight;
		this.rightHeight = rightHeight;
		this.leftSlope = leftSlope;
		this.rightSlope = rightSlope;
		this.bottomLeftRounded = bottomLeftRounded;
		this.topLeftRounded = topLeftRounded;
		this.topRightRounded = topRightRounded;
		this.bottomRightRounded = bottomRightRounded;
	}

	@Override
	protected boolean lineIsDrawn(int index, Polygon polygon) {
		return drawBottomLine || index < polygon.npoints - 1;
	}

	@Override
	protected Insets getShapedBorderInsets(Component c) {
		return new Insets(1, (isBottomLeftRounded(c) ? 4 : 1) + (topLeftRounded ? (leftSlope <= 0.5f ? 4 : 1) : 0) + (int) (leftSlope * leftHeight),
				drawBottomLine ? 1 : 0, (bottomRightRounded ? 4 : 1) + (topRightRounded ? (rightSlope <= 0.5f ? 4 : 1) : 0) + (int) (rightSlope * rightHeight));
	}

	protected boolean isBottomLeftRounded(Component c) {
		return bottomLeftRounded;
	}

	private static int[] getCorner(int type, float slope, boolean rounded) {
		return corners[type][!rounded ? 0 : type < 4 ? (slope >= 2f ? 1 : slope >= 1f ? 2 : 3) : (slope <= 0.5f ? 1 : slope <= 1f ? 2 : 3)];
	}

	private static void addPoint(int px, int py) {
		xCoords[index] = px;
		yCoords[index++] = py;
		x = px;
		y = py;
	}

	private static void addCorner(int px, int py, int[] c) {
		int cLength = c.length;
		for (int i = 0; i < cLength; i++) {
			addPoint(px + c[i++], py + c[i]);
		}
	}

	private static int getStartY(int[] corner) {
		return corner[1];
	}

	private static int getEndY(int[] corner) {
		return corner[corner.length - 1];
	}

	@Override
	protected Polygon createPolygon(Component c, int width, int height) {
		boolean bottomLeftRoundedTemp = isBottomLeftRounded(c);
		int leftX = (int) (leftHeight * leftSlope + (bottomLeftRoundedTemp ? 4 : 0));
		int rightX = width - 1 - (int) (rightHeight * rightSlope + (bottomRightRounded ? 4 : 0));
		int bottomY = height - (drawBottomLine ? 1 : 0);

		int[] topLeft = getCorner(1, leftSlope, topLeftRounded);
		int[] topRight = getCorner(2, rightSlope, topRightRounded);
		int[] bottomLeft = getCorner(0, leftSlope, bottomLeftRoundedTemp);
		int[] bottomRight = getCorner(3, rightSlope, bottomRightRounded);

		setIndex(0);
		setY(bottomY);
		int dy = height - getStartY(topLeft) + getEndY(bottomLeft);

		if (dy <= leftHeight) {
			setX(leftX - (int) (dy * leftSlope));
			addCorner(x, y, bottomLeft);
		} else {
			setX(leftX - (int) (leftHeight * leftSlope));
			addCorner(x, y, getCorner(0, 0, bottomLeftRoundedTemp));
			addPoint(x, getStartY(topLeft) + leftHeight);
		}

		addCorner(leftX, 0, topLeft);
		addCorner(rightX, 0, topRight);
		dy = height - getEndY(topRight) + getStartY(bottomRight);

		if (dy <= rightHeight) {
			addCorner((int) (rightX + dy * rightSlope), bottomY, bottomRight);
		} else {
			addPoint((int) (rightX + rightSlope * rightHeight), getEndY(topRight) + rightHeight);
			addCorner(x, bottomY, getCorner(3, 0, bottomRightRounded));
		}

		return new Polygon(xCoords, yCoords, index);
	}

}